package com.example.core.filter;

import com.example.common.config.Rule;
import com.example.common.constants.FilterConst;
import com.example.core.context.GatewayContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author Peng Yisheng
 * @Date 2024/12/1 21:41
 * @Description 过滤器链工厂实现类
 */
@Slf4j
public class GatewayFilterChainFactory implements FilterChainFactory {

    private static class SingletonInstance {
        private static final GatewayFilterChainFactory INSTANCE = new GatewayFilterChainFactory();
    }

    public static GatewayFilterChainFactory getInstance() {
        return SingletonInstance.INSTANCE;
    }

    /**
     * 过滤器实现类映射
     */
    private Map<String/** 过滤器id */, Filter> processorFilterIdMap = new ConcurrentHashMap<>();

    public GatewayFilterChainFactory() {
        // spi加载resource中配置的所有过滤器，这是网关能支持的过滤器，nacos配置的过滤器也应该是网关所支持的
        ServiceLoader<Filter> serviceLoader = ServiceLoader.load(Filter.class);
        serviceLoader.forEach(filter -> {
            FilterAspect annotation = filter.getClass().getAnnotation(FilterAspect.class);
            if (annotation == null) {
                return;
            }
            log.info("load filter success:{},{},{},{}", filter.getClass(), annotation.id(), annotation.name(), annotation.order());
            // 添加到过滤器集合
            String filterId = annotation.id();
            if (StringUtils.isEmpty(filterId)) {
                filterId = filter.getClass().getName();
            }
            processorFilterIdMap.put(filterId, filter);
        });

    }

    @Override
    public GatewayFilterChain buildFilterChain(GatewayContext ctx) throws Exception {
        // TODO：优化：过滤器链应该从缓存中拿，而不应该每次网关请求都构建一次
        return doBuildFilterChain(ctx.getRule());
    }

    /**
     * 通过rule构造过滤器链，一个rule对应n个filter(插件)
     *
     * @param rule
     * @return
     * @throws Exception
     */
    public GatewayFilterChain doBuildFilterChain(Rule rule) throws Exception {
        GatewayFilterChain chain = new GatewayFilterChain();
        List<Filter> filters = new ArrayList<>();
        // 全局过滤器：手动将某些过滤器加入到过滤器链中
        filters.add(getFilterInfo(FilterConst.GRAY_FILTER_ID));
        filters.add(getFilterInfo(FilterConst.MONITOR_FILTER_ID));
        filters.add(getFilterInfo(FilterConst.MONITOR_END_FILTER_ID));
        filters.add(getFilterInfo(FilterConst.MOCK_FILTER_ID));
        if (rule != null) {
            // 从rule中获取过滤器配置
            Set<Rule.FilterConfig> filterConfigs = rule.getFilterConfigs();
            Iterator iterator = filterConfigs.iterator();
            Rule.FilterConfig filterConfig;
            while (iterator.hasNext()) {
                filterConfig = (Rule.FilterConfig) iterator.next();
                if (filterConfig == null) {
                    continue;
                }
                String filterId = filterConfig.getId();
                if (StringUtils.isNotEmpty(filterId) && getFilterInfo(filterId) != null) {
                    Filter filter = getFilterInfo(filterId);
                    filters.add(filter);
                }
            }
        }
        // 添加路由过滤器-这是最后一步
        filters.add(getFilterInfo(FilterConst.ROUTER_FILTER_ID));
        // 排序，按从小到大执行
        filters.sort(Comparator.comparingInt(Filter::getOrder));
        // 添加到链表中
        chain.addFilterList(filters);
        return chain;
    }

    @Override
    public Filter getFilterInfo(String filterId) throws Exception {
        return processorFilterIdMap.get(filterId);
    }
}
